import { MoveDirectionEnum } from "./Enum";
import { Square } from "./Square";
import { SquareGroup } from "./SquareGroup";
import { IPoint, Shape } from "./Type";
import panelConf from "./config/panelConf";

function isIPoint(obj: any): obj is IPoint {
  return obj && typeof obj.x !== "undefined";
}

export class TetrisRule {
  /**
   * 是否可以移动
   * @param {Shape} shape 形状
   * @param {IPoint} targetPoint
   */
  static isCanMove(shape: Shape, targetPoint: IPoint, esists: Square[]) {
    const targetShape: Shape = shape.map((p) => ({
      x: p.x + targetPoint.x,
      y: p.y + targetPoint.y,
    }));

    // 是否重合已有方块
    if (targetShape.some((sq) => esists.some((e) => e.point.x === sq.x && e.point.y === sq.y))) {
      return false;
    }
    // 是否移出边界
    return !targetShape.some((p) => p.x < 0 || p.x > panelConf.width - 1 || p.y < 0 || p.y > panelConf.height - 1);
  }

  static move(squareGroup: SquareGroup, targetPoint: IPoint, esists: Square[]): boolean;
  static move(squareGroup: SquareGroup, targetPoint: MoveDirectionEnum, esists: Square[]): boolean;
  static move(squareGroup: SquareGroup, targetPoint: IPoint | MoveDirectionEnum, esists: Square[]) {
    if (isIPoint(targetPoint)) {
      if (this.isCanMove(squareGroup.shape, targetPoint, esists)) {
        squareGroup.centerPoint = targetPoint;
        return true;
      }
      return false;
    } else {
      let targetCenterPoint: IPoint = { x: 0, y: 0 };

      switch (targetPoint) {
        case MoveDirectionEnum.left: {
          targetCenterPoint = {
            x: squareGroup.centerPoint.x - 1,
            y: squareGroup.centerPoint.y,
          };
          break;
        }
        case MoveDirectionEnum.right: {
          targetCenterPoint = {
            x: squareGroup.centerPoint.x + 1,
            y: squareGroup.centerPoint.y,
          };
          break;
        }
        case MoveDirectionEnum.down: {
          targetCenterPoint = {
            x: squareGroup.centerPoint.x,
            y: squareGroup.centerPoint.y + 1,
          };
          break;
        }
      }
      return this.move(squareGroup, targetCenterPoint, esists);
    }
  }

  /**
   * 移动到该方向的终点
   */
  static moveToEnd(squareGroup: SquareGroup, direct: MoveDirectionEnum, esists: Square[]) {
    while (this.move(squareGroup, direct, esists)) {}
  }

  /**
   * 旋转
   * @returns
   */
  static rotate(squareGroup: SquareGroup, esists: Square[]): boolean {
    const isRotate = this.isCanMove(squareGroup.afterRotateShape(), squareGroup.centerPoint, esists);
    if (isRotate) {
      squareGroup.rotate();
      return true;
    }
    return false;
  }

  /**
   * 消除
   */
  static clearSquare(esists: Square[]): number {
    const ys = esists.map((sq) => sq.point.y);
    const minY = Math.min(...ys);
    const maxY = Math.max(...ys);

    let count = 0;
    for (let y = minY; y <= maxY; y++) {
      if (this.clear(esists, y)) {
        count++;
      }
    }
    return count;
  }

  private static clear(esists: Square[], y: number): boolean {
    const ys = esists.filter((sq) => sq.point.y === y);
    if (ys.length === panelConf.width) {
      ys.forEach((sq) => {
        // 从视图上删除
        sq.viewer?.remove();

        // 将该行的方块从esists中删除
        const index = esists.indexOf(sq);
        esists.splice(index, 1);
      });

      // 将该行前面的y坐标+1
      esists.filter((sq) => sq.point.y < y).forEach((sq) => {
        sq.point = {
          x: sq.point.x,
          y: sq.point.y + 1,
        };
      });
      return true;
    }
    return false;
  }
}
